# -*- coding:utf-8 -*-
"""
@author: ksf

@since: 2020/9/18 5:46 PM
"""

import os
import shutil
import yaml
from collections import namedtuple

from .utils import ensure_directory, merge_dict
from .logger import sys_logger
from vcat import LUCKY_CAT_PATH

ROOT_PATH = os.path.dirname(os.path.dirname(__file__))


ConfigPathNameTuple = namedtuple('ConfigPathNameTuple', field_names=('path', 'filename'))


class BaseConfigManager:

    CUSTOM_DIR = os.environ.get(LUCKY_CAT_PATH, None)
    if CUSTOM_DIR is None:
        CUSTOM_DIR = os.path.expanduser(r'~\.vcat')
    ensure_directory(CUSTOM_DIR)

    # 需要遍历的配置文件文件夹+文件名
    SEARCH_PATHS = (ConfigPathNameTuple(ROOT_PATH, 'config.yml'),
                    ConfigPathNameTuple(CUSTOM_DIR, 'config.engine.yml'))

    def __init__(self, app_name=None):
        self._app_name = app_name
        self._config_obj = self.merge_all()

    def get_root_dir(self, name):
        """
        获取 root 目录
        :return:
        """
        return self.SEARCH_PATHS[0].path

    def get_root_config_path(self):
        """
        获取root目录下自带配置文件路径
        :return:
        """
        root_config = self.SEARCH_PATHS[0]
        return os.path.join(root_config.path.format(name=self._app_name), root_config.filename.format(name=self._app_name))

    @classmethod
    def get_user_dir(cls):
        """
        用户配置目录. 用于放置数据和配置
        """
        return cls.CUSTOM_DIR

    def get_user_config_path(self):
        """
        获取用户家目录下用户自定义配置文件路径
        :return:
        """
        root_config = self.SEARCH_PATHS[-1]
        return os.path.join(root_config.path.format(name=self._app_name), root_config.filename.format(name=self._app_name))

    def get_config(self):
        return self._config_obj

    def merge_all(self):
        """
        遍历配置文件、合并所有config，后面的配置会覆盖前面的同名配置
        :return:
        """
        out = {}
        for config_path in self.SEARCH_PATHS:
            print(config_path)
            file_path = os.path.join(config_path.path.format(name=self._app_name),
                                     config_path.filename.format(name=self._app_name))
            try:
                config_obj = self.read_yml(file_path)
            except FileNotFoundError:
                pass
            out = merge_dict(out, config_obj)
        return out

    @staticmethod
    def read_yml(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            config_obj = yaml.safe_load(f)
            return config_obj

    def generate_config_file(self, directory=None):
        """
        生成配置文件
        :param directory: 配置文件保存的目录. 若为 None 则保存在默认位置
        :return: 生成的配置文件路径
        """
        if not directory:
            directory = self.get_user_dir()
        ensure_directory(directory)
        shutil.copy(self.get_root_config_path(), self.get_user_config_path())
        sys_logger.info(f"generate config file: {self.get_user_config_path()}")
        return self.get_user_config_path()

    def get_version(self):
        """
        获取 当前插件 版本
        :return:
        """
        try:
            with open(os.path.join(self.get_root_dir(self._app_name), 'VERSION.txt'), 'r', encoding='utf-8') as f:
                return f.read()
        except (FileExistsError, FileNotFoundError):
            return '0.0.0'

    def from_dict(self, d):
        """
        从字典生成配置
        :param d:
        :return:
        """
        self._config_obj = merge_dict(self._config_obj, d)
        return self

    def save(self):
        """
        保存到用户家目录的配置文件
        项目目录配置文件不支持自动保存，只能手动修改
        :return:
        """
        path = self.get_user_config_path()
        with open(path, appe='w+') as f:
            yaml.safe_dump(self._config_obj, stream=f)


class AppConfigManager(BaseConfigManager):

    CUSTOM_DIR = os.environ.get(LUCKY_CAT_PATH, None)
    if CUSTOM_DIR is None:
        CUSTOM_DIR = os.path.expanduser(r'~\.vcat')
    ensure_directory(CUSTOM_DIR)

    SEARCH_PATHS = (ConfigPathNameTuple(os.path.join(ROOT_PATH, 'apps', '{name}'), 'config.yml'),
                    ConfigPathNameTuple(os.path.join(ROOT_PATH, 'apps', '{name}'), 'config.yml'),
                    ConfigPathNameTuple(os.path.join(CUSTOM_DIR, 'config'), 'config.app.{name}.yml'))


class BrokerConfigManager(BaseConfigManager):

    CUSTOM_DIR = os.environ.get(LUCKY_CAT_PATH, None)
    if CUSTOM_DIR is None:
        CUSTOM_DIR = os.path.expanduser(r'~\.vcat')
    ensure_directory(CUSTOM_DIR)

    SEARCH_PATHS = (ConfigPathNameTuple(os.path.join(ROOT_PATH, 'gateway', '{name}'), 'config.yml'),
                    ConfigPathNameTuple(os.path.join(CUSTOM_DIR, 'config'), 'config.broker.{name}.yml'))


